#include "halton.h"
#include "../core/sampling.h"

HaltonSampler::HaltonSampler(int xstart, int xend, int ystart, int yend, int spp, bool lns, bool ts) :
				Sampler(xstart, xend, ystart, yend, spp, lns, ts) {
	int delta = max(xPixelEnd - xPixelStart,yPixelEnd - yPixelStart);
	wantedSamples = samplePerPixel * delta * delta;
	currentSample = 0;
	rng = new RNG(xstart + ystart *(xend - xstart));
}
HaltonSampler::~HaltonSampler() {
	SAFE_DELETE(rng);
}

Sampler *HaltonSampler::GetSubSampler(int num, int count) {
	int x0, x1, y0, y1;
	ComputeSubWindow(num, count, &x0, &x1, &y0, &y1);
	if (x0 == x1 || y0 == y1) 
		return NULL;
	return new HaltonSampler(x0, x1, y0, y1, wantedSamples, needLensSamples, needTimeSamples);
}

int HaltonSampler::GetMoreSamples(Sample *sample) {
retry:
	if(currentSample >= wantedSamples)
		return 0;
	// Generate image sample, may out of image extent
	float u = (float)RadicalInverse(currentSample, 3);
	float v = (float)RadicalInverse(currentSample, 2);

	int delta = max(xPixelEnd-xPixelStart, yPixelEnd-yPixelStart);

	float imageX, imageY;
	imageX = Lerp(u,xPixelStart, xPixelStart + delta);
	imageY = Lerp(v,yPixelStart, yPixelStart + delta);
	currentSample++;
	if(imageX > xPixelEnd || imageY > yPixelEnd)
		goto retry;	// evil goto...
	sample->imageSample = Point2(imageX, imageY);
	if(needLensSamples)
		sample->lensSample = Point2((float)RadicalInverse(currentSample, 5),(float)RadicalInverse(currentSample, 7));
	else
		sample->lensSample = Point2(0., 0.);
	if(needTimeSamples)
		sample->time = (float)RadicalInverse(currentSample, 11);
	else
		sample->time = 0.;

	// Generate samplers for integrator
	for(int j = 0; j < sample->n1D.size(); j++)
		LatinHypercube1D(sample->oneD[j], sample->n1D[j], rng);
	for(int j = 0; j < sample->n2D.size(); j++)
		LatinHypercube2D(sample->twoD[j], sample->n2D[j], rng);

	return 1;
}